package com.colodoo.framework.creater.service;

import com.colodoo.framework.creater.config.CreaterCfg;
import com.colodoo.framework.creater.model.BaseParm;
import com.colodoo.framework.creater.model.Column;
import com.colodoo.framework.creater.model.DatagridParm;
import com.colodoo.framework.creater.model.Tables;
import com.colodoo.framework.easyui.Page;
import com.colodoo.framework.utils.StringUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import org.mybatis.generator.config.JavaModelGeneratorConfiguration;
import org.mybatis.generator.config.SqlMapGeneratorConfiguration;
import org.mybatis.generator.config.TableConfiguration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 逆向工程,从数据库生成生成相应的代码
 *
 * @author colodoo
 */
@Service
public class CreaterService {

    /* Mybatis Generator相关 */
    private final static String MYBATIS_GENERATOR_XML_PATH = "\\src\\main\\resources\\generatorConfig.xml";

    /* 路径相关 */
    private final static String JAVA_ROOT_PATH = "\\src\\main\\java\\";

    /* 模板相关 */
    private final static String TMP_DATAGRID_PATH = "\\src\\main\\resources\\templates\\creater\\datagrid";
    private final static String TMP_ROOT_PATH = "\\src\\main\\resources\\templates\\manager\\";

    /* 菜单相关 */
    private final static String DEFAULT_PARENT_MENU_ID = "349cb244e3e64a0a92a6721879f624d4";

    @Resource
    CreaterMapper createrMapper;
    @Resource
    CreaterCfg createrCfg;
	/*@Resource
	MenuService menuService;*/

    /**
     * 取查询语句，采用模板方式
     *
     * @param tableName
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    @Deprecated
    public String getSelectQueryByTemplate(String tableName) throws IOException, TemplateException {
        String resultStr = "";
        Configuration configuration = new Configuration();
        File dir = ResourceUtils.getFile("classpath:creater");
        configuration.setDirectoryForTemplateLoading(dir);
        configuration.setObjectWrapper(new DefaultObjectWrapper());
        configuration.setDefaultEncoding("UTF-8");
        Template template = configuration.getTemplate("select.ftl");
        Map<String, Object> paramMap = new HashMap<String, Object>();
        List<Column> columns = createrMapper.getColumns(tableName, createrCfg.getTableSchema());
        for (Column column : columns) {
            column.set_columnName(StringUtil.underlineToCamel(column.getColumnName()));
        }
        paramMap.put("columns", columns);
        paramMap.put("tableName", tableName);
        StringWriter writer = new StringWriter();
        template.process(paramMap, writer);
        return writer.toString();
    }

    /**
     * 创建Mybatis字符串
     *
     * @param mybatisParm
     * @return
     */
    public String createMybatisString(BaseParm mybatisParm) {
        String result = "";
        try {
            List<String> warnings = new ArrayList<>();
            boolean overwrite = true;
            File configFile = new File(createrCfg.getSrcPath() + MYBATIS_GENERATOR_XML_PATH);
            ConfigurationParser cp = new ConfigurationParser(warnings);
            org.mybatis.generator.config.Configuration config = cp.parseConfiguration(configFile);
            for (Context ctx : config.getContexts()) {
                // 设置数据库
                JDBCConnectionConfiguration jdbcConnectionConfiguration = ctx.getJdbcConnectionConfiguration();
                jdbcConnectionConfiguration.setConnectionURL(createrCfg.getUrl());
                // 设置model生成位置
                JavaModelGeneratorConfiguration model = ctx.getJavaModelGeneratorConfiguration();
                model.setTargetPackage(mybatisParm.getPackageName() + ".model");
                model.setTargetProject(createrCfg.getSrcPath() + "/src/main/java");
                model.getProperties().setProperty("enableSubPackages", "true");
                model.getProperties().setProperty("trimStrings", "true");
                // 设置xml文件生成位置
                SqlMapGeneratorConfiguration sqlMapper = ctx.getSqlMapGeneratorConfiguration();
                sqlMapper.setTargetPackage(mybatisParm.getPackageName() + ".service");
                sqlMapper.setTargetProject(createrCfg.getSrcPath() + "/src/main/java");
                sqlMapper.getProperties().setProperty("enableSubPackages", "true");
                // 设置mapper接口文件生成位置
                JavaClientGeneratorConfiguration javaMapper = ctx.getJavaClientGeneratorConfiguration();
                javaMapper.setTargetPackage(mybatisParm.getPackageName() + ".service");
                javaMapper.setTargetProject(createrCfg.getSrcPath() + "/src/main/java");
                javaMapper.getProperties().setProperty("enableSubPackages", "true");
                // 配置表信息
                ctx.getTableConfigurations().clear();
                TableConfiguration tableCfg = new TableConfiguration(ctx);
                tableCfg.setTableName(mybatisParm.getTableName());
                tableCfg.setDomainObjectName(
                        StringUtil.upperCase(StringUtil.underlineToCamel(mybatisParm.getTableName())));
                ctx.getTableConfigurations().add(tableCfg);
            }
            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);

            // 生成VO类
            this.modelVOCreate(mybatisParm);

            result = "create mybatis done.";
        } catch (Exception e) {
            result = "create mybatis error.";
            e.printStackTrace();
        }
        return result;
    }

    public void modelVOCreate(BaseParm serviceParm) throws Exception {
        // 参数处理
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("tableName", StringUtil.underlineToCamel2(serviceParm.getTableName()));
        paramMap.put("packageName", serviceParm.getPackageName());

        String resultDirStr = createrCfg.getSrcPath() + JAVA_ROOT_PATH + serviceParm.getPackageName().replace(".", "\\")
                + "\\model";
        String mapperDirStr = resultDirStr + "";
        File mapperDir = new File(mapperDirStr);
        if (!mapperDir.exists()) {
            mapperDir.mkdirs();
        }
        String mapperTargetFileName = StringUtil.upperCase(StringUtil.underlineToCamel(serviceParm.getTableName()))
                + "VO.java";
        Writer mapperWriter = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(new File(mapperDirStr + "\\" + mapperTargetFileName)), "UTF-8"));
        Configuration mapperConfiguration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        File mapperTemplateDir = new File("src\\main\\resources\\creater");
        mapperConfiguration.setDirectoryForTemplateLoading(mapperTemplateDir);
        mapperConfiguration.setObjectWrapper(new DefaultObjectWrapper(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
        mapperConfiguration.setDefaultEncoding("UTF-8");
        Template mapperTemplate = mapperConfiguration.getTemplate("modelVO.ftl");
        mapperTemplate.process(paramMap, mapperWriter);
        mapperWriter.close();
    }

    /**
     * 创建接口类
     *
     * @param actionParm
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    public String createActionString(BaseParm actionParm) throws IOException, TemplateException {
        String resultStr = "";
        StringWriter writer = new StringWriter();
        String resultDirStr = createrCfg.getSrcPath() + JAVA_ROOT_PATH + actionParm.getPackageName().replace(".", "\\")
                + "\\action";
        File resultDir = new File(resultDirStr);
        if (!resultDir.exists()) {
            resultDir.mkdir();
        }
        String targetFileName = StringUtil.upperCase(StringUtil.underlineToCamel(actionParm.getTableName()))
                + "Action.java";
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        File dir = new File("src\\main\\resources\\creater");
        configuration.setDirectoryForTemplateLoading(dir);
        configuration.setObjectWrapper(new DefaultObjectWrapper(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
        configuration.setDefaultEncoding("UTF-8");
        Template template = configuration.getTemplate("action.ftl");
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("tableName", StringUtil.underlineToCamel2(actionParm.getTableName()));
        paramMap.put("packageName", actionParm.getPackageName());
        Writer writer1 = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(new File(resultDirStr + "\\" + targetFileName)), "UTF-8"));
        template.process(paramMap, writer);
        template.process(paramMap, writer1);
        resultStr = writer.toString();
        writer.close();
        writer1.close();
        // System.out.println(resultStr);
        return resultStr;
    }

    /**
     * 生成服务类代码
     *
     * @param serviceParm
     * @return
     * @throws Exception
     */
    public String createServiceString(BaseParm serviceParm) throws Exception {
        String resultStr = "";
        // 参数处理
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("tableName", StringUtil.underlineToCamel2(serviceParm.getTableName()));
        paramMap.put("packageName", serviceParm.getPackageName());

        StringWriter writer = new StringWriter();
        String resultDirStr = createrCfg.getSrcPath() + JAVA_ROOT_PATH + serviceParm.getPackageName().replace(".", "\\")
                + "\\service";
        File resultDir = new File(resultDirStr);
        if (!resultDir.exists()) {
            resultDir.mkdir();
        }
        String targetFileName = StringUtil.upperCase(StringUtil.underlineToCamel(serviceParm.getTableName()))
                + "Service.java";
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        File dir = new File("src\\main\\resources\\creater");
        configuration.setDirectoryForTemplateLoading(dir);
        configuration.setObjectWrapper(new DefaultObjectWrapper(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
        configuration.setDefaultEncoding("UTF-8");
        Template template = configuration.getTemplate("service.ftl");
        Writer writer1 = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(new File(resultDirStr + "\\" + targetFileName)), "UTF-8"));
        template.process(paramMap, writer);
        template.process(paramMap, writer1);
        resultStr = writer.toString();
        writer.close();
        writer1.close();

        // mapper接口部分生成
        this.mapperInterfaceCreate(serviceParm);
        // mapper配置文件部分
        this.mapperXmlCreates(serviceParm);

        return resultStr;
    }

    /**
     * mapper配置文件生成
     *
     * @param serviceParm
     * @throws Exception
     */
    private void mapperXmlCreates(BaseParm serviceParm) throws Exception {
        // 参数处理
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("tableName", StringUtil.underlineToCamel2(serviceParm.getTableName()));
        paramMap.put("packageName", serviceParm.getPackageName());
        paramMap.put("SQLstring", this.getSelectQueryByTemplate(serviceParm.getTableName()));

        String resultDirStr = createrCfg.getSrcPath() + JAVA_ROOT_PATH + serviceParm.getPackageName().replace(".", "\\")
                + "\\service";
        String mapperDirStr = resultDirStr + "\\mapper";
        File mapperDir = new File(mapperDirStr);
        if (!mapperDir.exists()) {
            mapperDir.mkdirs();
        }
        String mapperTargetFileName = StringUtil.upperCase(StringUtil.underlineToCamel(serviceParm.getTableName()))
                + "SQLMapper.xml";
        Writer mapperWriter = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(new File(mapperDirStr + "\\" + mapperTargetFileName)), "UTF-8"));
        Configuration mapperConfiguration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        File mapperTemplateDir = new File("src\\main\\resources\\creater\\mapper");
        mapperConfiguration.setDirectoryForTemplateLoading(mapperTemplateDir);
        mapperConfiguration.setObjectWrapper(new DefaultObjectWrapper(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
        mapperConfiguration.setDefaultEncoding("UTF-8");
        Template mapperTemplate = mapperConfiguration.getTemplate("SQLMapperXml.ftl");
        mapperTemplate.process(paramMap, mapperWriter);
        mapperWriter.close();
    }

    /**
     * mapper接口文件生成
     *
     * @param serviceParm
     * @throws Exception
     */
    public void mapperInterfaceCreate(BaseParm serviceParm) throws Exception {

        // 参数处理
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("tableName", StringUtil.underlineToCamel2(serviceParm.getTableName()));
        paramMap.put("packageName", serviceParm.getPackageName());

        String resultDirStr = createrCfg.getSrcPath() + JAVA_ROOT_PATH + serviceParm.getPackageName().replace(".", "\\")
                + "\\service";
        String mapperDirStr = resultDirStr + "\\mapper";
        File mapperDir = new File(mapperDirStr);
        if (!mapperDir.exists()) {
            mapperDir.mkdirs();
        }
        String mapperTargetFileName = StringUtil.upperCase(StringUtil.underlineToCamel(serviceParm.getTableName()))
                + "SQLMapper.java";
        Writer mapperWriter = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(new File(mapperDirStr + "\\" + mapperTargetFileName)), "UTF-8"));
        Configuration mapperConfiguration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        File mapperTemplateDir = new File("src\\main\\resources\\creater\\mapper");
        mapperConfiguration.setDirectoryForTemplateLoading(mapperTemplateDir);
        mapperConfiguration.setObjectWrapper(new DefaultObjectWrapper(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
        mapperConfiguration.setDefaultEncoding("UTF-8");
        Template mapperTemplate = mapperConfiguration.getTemplate("SQLMapper.ftl");
        mapperTemplate.process(paramMap, mapperWriter);
        mapperWriter.close();
    }

    /**
     * 创建增删改查前端代码
     * <p>
     * 1、tableName 表名 2、menuName 功能名 3、menuTitle 菜单标题 4、PK 主键
     *
     * @param datagridParm
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    public String createDatagridString(DatagridParm datagridParm) throws IOException, TemplateException {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        String tableName = datagridParm.getTableName();
        // 功能名
        String menuName = datagridParm.getMenuName();
        // 功能标题
        String menuTitle = datagridParm.getMenuTitle();

        // 填充变量
        paramMap.put("tableName", StringUtil.underlineToCamel(tableName));
        paramMap.put("menuName", menuName);
        paramMap.put("menuTitle", menuTitle);

        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

        // 目标目录字符串
        String targetDirPath = createrCfg.getSrcPath() + TMP_ROOT_PATH + StringUtil.underlineToCamel(tableName);
        // 目标目录
        File targetDir = new File(targetDirPath);

        // 如果不存在目标目录,则创建新的目录
        if (!targetDir.exists()) {
            targetDir.mkdir();
        }
        // 模板目录
        File dir = new File(createrCfg.getSrcPath() + TMP_DATAGRID_PATH);
        configuration.setDirectoryForTemplateLoading(dir);
        configuration.setObjectWrapper(new DefaultObjectWrapper(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
        configuration.setDefaultEncoding("UTF-8");
        Template template = configuration.getTemplate("datagrid-base-crud-js.ftl");
        List<Column> columns = createrMapper.getColumns(tableName, createrCfg.getTableSchema());

        // 时间类型修改控件
        for (Column column : columns) {
            column.set_columnName(StringUtil.underlineToCamel(column.getColumnName()));
            String columnType = column.getColumnType();
            if (columnType.contains("datetime")) {
                column.setColumnType("easyui-datetimebox");
            } else {
                column.setColumnType("easyui-textbox");
            }
            if ("PRI".equals(column.getColumnKey())) {
                paramMap.put("PK", column.get_columnName());
            }
        }
        paramMap.put("columns", columns);

        // 目标文件名
        String targetFileName = menuName + ".ftl";

        // 写带字符串变量中
        StringWriter writer = new StringWriter();
        template.process(paramMap, writer);
        // 写入文件
        Writer writer1 = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(new File(targetDirPath + "\\" + targetFileName)), "UTF-8"));
        template.process(paramMap, writer1);

        return writer.toString();
    }

    /**
     * 创建实体类字符串
     *
     * @param tableName
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    @Deprecated
    public String createModelString(String tableName) throws IOException, TemplateException {
        String resultStr = "";
        Configuration configuration = new Configuration();
        File dir = ResourceUtils.getFile("classpath:creater");
        configuration.setDirectoryForTemplateLoading(dir);
        configuration.setObjectWrapper(new DefaultObjectWrapper());
        configuration.setDefaultEncoding("UTF-8");
        Template template = configuration.getTemplate("model.ftl");
        Map<String, Object> paramMap = new HashMap<String, Object>();
        List<Column> columns = createrMapper.getColumns(tableName, createrCfg.getTableSchema());
        for (Column column : columns) {
            String columnType = column.getColumnType();
            if (columnType.contains("varchar")) {
                column.setColumnType("String");
            }
            if (columnType.contains("datetime")) {
                column.setColumnType("Date");
            }
            if (columnType.contains("int")) {
                column.setColumnType("int");
            }
            column.set_columnName(StringUtil.underlineToCamel(column.getColumnName()));
        }
        paramMap.put("packageName", "com.colodoo");
        paramMap.put("columns", columns);
        tableName = StringUtil.underlineToCamel(tableName);
        paramMap.put("tableName", tableName);
        String resultFile = dir.getAbsolutePath() + "/model.java";
        StringWriter writer = new StringWriter();
        template.process(paramMap, writer);
        return writer.toString();
    }

    /**
     * 取所有表格
     *
     * @return
     */
    public PageInfo<Tables> getTables(Page page) {
        PageInfo<Tables> pageInfo;
        List<Tables> list = null;
        PageHelper.startPage(page.getPage(), page.getRows());
        list = createrMapper.getTables(createrCfg.getTableSchema());
        pageInfo = new PageInfo<Tables>(list);
        return pageInfo;
    }
}
